
from PIL import Image
import os
import base64
import re


def phtot_base64(address):#将地址为address的图片转为base64字符串
    with open(address,"rb") as photo:
        pb=base64.b64encode(photo.read())
        return str(pb)[2:-1]

# 获取文件大小:KB
def get_size(file):
    size = os.path.getsize(file)
    return size / 1024


def compress_image(infile_path, outfile_path, aim_size, step=10, quality=80):
    """不改变图片尺寸压缩到指定大小
    :param infile: 压缩源文件
    :param outfile: 压缩文件保存地址
    :param mb: 压缩目标，KB
    :param step: 每次调整的压缩比率
    :param quality: 初始压缩比率
    :return: 压缩文件地址，压缩文件大小
    """
    o_size = get_size(infile_path)
    if o_size <= aim_size:
        im = Image.open(infile_path)
        im = im.convert('RGB')
        im.save(outfile_path, quality=quality)
        print("图片已被压缩!")
        return infile_path

    while o_size > aim_size:
        im = Image.open(infile_path)
        im = im.convert('RGB')
        im.save(outfile_path, quality=quality)
        if quality - step < 0:
            break
        quality -= step
        o_size = get_size(outfile_path)

    print("图片已被压缩!")
    return outfile_path


if __name__=="__main__":

    # #-----------------------------------------------------------------
    # # 参数定义
    # #-----------------------------------------------------------------
    # 路径获取
    print(" ")
    print("*"*30)
    target_path = input("请输入目标markdown文件地址: \n")  # 例如:"D:\Markdown\Note\Machine learning\误差与噪音.md"(两侧有引号,这也就是你选中md文件,然后shift+右键,复制路径得到的结果)
    print("*"*30)
    
    # 图片大小获取
    print(" ")
    print("*"*30)
    pic_aim_size = float( input("请输入压缩图片允许最大体积(单位：KB): ") )
    print("*"*30)


    # #-----------------------------------------------------------------
    # # 主程序
    # #-----------------------------------------------------------------
    
    # 为解决跨平台问题，统一用 "\" 分隔路径
    target_path = target_path.replace("\\","/")
    if '"' in target_path:
        target_path = eval(target_path)
    
    # 打开目标文件(原始md文件)
    with open(target_path,"r",encoding="utf-8") as md:

        # 初始化
        pic_num = 0  # 图片序号
        base64_pic_quote_list = []

        # 创建/打开 新的转换后的文件 
        transformed = open(target_path[0:-3]+"_transformed.md","w",encoding="utf-8")  # 在目标文件同一文件夹地址下产生转换后文件
        
        # 对原文件逐行遍历
        for line in md:

            # 如果匹配到图片
            if(re.search("!\[[^]]*\].*",line)):  # 匹配到图片格式
                # 保存图片地址
                raw_img_path = re.search("(?<=\()[^\)]*",line).group().replace("\\","/")  # 提取图片地址并且将反斜杠转换为斜杠
                
                # 如果是本地图片
                if not(re.match("data",raw_img_path) or re.match("http",raw_img_path)): # 确定是本地图片
                    
                    # 图片序号加1，第 pic_num 张图片
                    pic_num = pic_num + 1
                    
                    # 提取图片名 [pic_name]
                    pic_name = re.search("\[.*?\]",line).group()[1:-1]
                    
                    # 图片引用名 如 ![avatar][base64str] ref: https://www.jianshu.com/p/280c6a6f2594
                    pic_num_str = "Fig" + str(pic_num)  # 图片引用名
                    pic_new_quote = "![" + pic_name + "][" + pic_num_str + "]"  # 图片引用行
                    
                    # 替换文件引用行到源字符串
                    line = re.sub("!\[[^]]*\]\([^)]*\)",pic_new_quote,line)  

                    # 展示被压缩文件
                    print("")
                    print("*"*30)
                    print("图片:【" + raw_img_path + "】被读取!")

                    # base64被引用行添加到列表，准备在文件最后列出
                    base64_pic_quote = "[" + pic_num_str + "]:data:image/png;base64," + phtot_base64(raw_img_path)  # 将图片格式转为base64格式
                    
                    # 交互信息
                    print("")
                    print("原始图像base64文本长度为:" + str( len(phtot_base64(raw_img_path)) ) )
                    
                    # 图片压缩
                    compressed_img_dpath = './pic_compressed/'
                    if not os.path.exists(compressed_img_dpath):
                        os.makedirs(compressed_img_dpath)
                    compressed_img_fpath = compressed_img_dpath + pic_name + '.jpg'
                    compressed_img_fpath = compress_image(raw_img_path,compressed_img_fpath, pic_aim_size)
                    
                    # 压缩图片转base64
                    base64_pic_quote = "[" + pic_num_str + "]:data:image/png;base64," + phtot_base64(compressed_img_fpath)  # 将图片格式转为base64格式
                    base64_pic_quote_list.append(base64_pic_quote)
                    
                    # 交互信息
                    print("压缩图像base64文本长度为:" + str( len(phtot_base64(compressed_img_fpath)) ) )                  
                    print("*"*30 ) 

            transformed.write(line) # 写入一行
        

        # 在最后添加 base_64 的ref
        transformed.write("\n")
        transformed.write("\n")
        transformed.write("*"*100 + "\n")
        transformed.write("  \n")
        transformed.write("*"*100 + "\n")
        transformed.write("  \n")
        transformed.write("*"*100 + "\n") 
        transformed.write("\n")
        for base64_pic_quote in base64_pic_quote_list:
            transformed.write(base64_pic_quote)
            transformed.write("\n")
        
        transformed.close()

        # 交互信息
        print("")
        print("")
        print("*"*30)
        print("文件图片转换成功！")
        print("*"*30)
    
    os.system("pause")